using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JTLeigh.Tools.Development.CopySourceAsHtml.UnitTests
{

    /// <summary>
    /// Unit tests for the <see cref="HtmlFile"/> class.
    /// </summary>
    [TestClass]
    public class HtmlFileFixture
    {
        #region Methods

        #region Append

        /// <summary>
        /// Ensures <see cref="HtmlFile.Append"/> appends the character to the current line's 
        /// current block.
        /// </summary>
        [TestMethod]
        public void TestAppend()
        {
            HtmlFile file;

            file = new HtmlFile();

            file.Append('T', 4);
            file.Append('e', 4);
            file.Append('s', 4);
            file.Append('t', 4);
            file.Append('1', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual("Test1", file.Lines[0].Blocks[0].GetHtml(false, 0, 4));

            file.PushBlock();
            file.Append('T', 4);
            file.Append('e', 4);
            file.Append('s', 4);
            file.Append('t', 4);
            file.Append('2', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual("Test2", file.Lines[0].Blocks[1].GetHtml(false, 0, 4));

            file.StartNewLine();
            file.Append('T', 4);
            file.Append('e', 4);
            file.Append('s', 4);
            file.Append('t', 4);
            file.Append('3', 4);
            Assert.AreEqual(2, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[1].Blocks.Count);
            Assert.AreEqual("Test3", file.Lines[1].Blocks[0].GetHtml(false, 0, 4));
        }

        #endregion // Append

        #region StartNewLine

        /// <summary>
        /// Ensures <see cref="HtmlFile.StartNewLine"/> creates a new line and, within that line,
        /// creates a new block based on the current block's settings.
        /// </summary>
        [TestMethod]
        public void TestStartNewLine()
        {
            const int testForegroundColor = 1;
            const int testBackgroundColor = 2;
            const bool testBold = true;

            HtmlFile file;

            file = new HtmlFile();
            file.SetForegroundColor(testForegroundColor);
            file.SetBackgroundColor(testBackgroundColor);
            file.SetBold(testBold);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[0].Blocks[0].ForegroundColor);
            Assert.AreEqual(testBackgroundColor, file.Lines[0].Blocks[0].BackgroundColor);
            Assert.AreEqual(testBold, file.Lines[0].Blocks[0].Bold);

            file.StartNewLine();
            Assert.AreEqual(2, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[1].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[1].Blocks[0].ForegroundColor);
            Assert.AreEqual(testBackgroundColor, file.Lines[1].Blocks[0].BackgroundColor);
            Assert.AreEqual(testBold, file.Lines[1].Blocks[0].Bold);
 
            file.StartNewLine();
            Assert.AreEqual(3, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[2].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[2].Blocks[0].ForegroundColor);
            Assert.AreEqual(testBackgroundColor, file.Lines[2].Blocks[0].BackgroundColor);
            Assert.AreEqual(testBold, file.Lines[2].Blocks[0].Bold);
        }

        #endregion // StartNewLine

        #region PushBlock

        /// <summary>
        /// </summary>
        [TestMethod]
        public void TestPushBlockPopBlock()
        {
            const int testForegroundColor = 1;
            const int testBackgroundColor = 2;
            const bool testBold = true;

            HtmlFile file;

            file = new HtmlFile();
            file.SetForegroundColor(testForegroundColor);
            file.SetBackgroundColor(testBackgroundColor);
            file.SetBold(testBold);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[0].Blocks[0].ForegroundColor);
            Assert.AreEqual(testBackgroundColor, file.Lines[0].Blocks[0].BackgroundColor);
            Assert.AreEqual(testBold, file.Lines[0].Blocks[0].Bold);

            file.PushBlock();
            file.SetForegroundColor(0);
            file.SetBackgroundColor(0);
            file.SetBold(!testBold);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(0, file.Lines[0].Blocks[1].ForegroundColor);
            Assert.AreEqual(0, file.Lines[0].Blocks[1].BackgroundColor);
            Assert.AreEqual(!testBold, file.Lines[0].Blocks[1].Bold);

            file.PopBlock();
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(3, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[0].Blocks[2].ForegroundColor);
            Assert.AreEqual(testBackgroundColor, file.Lines[0].Blocks[2].BackgroundColor);
            Assert.AreEqual(testBold, file.Lines[0].Blocks[2].Bold);
        }

        #endregion // PushBlock

        #region SetForegroundColor

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetForegroundColor"/> sets the foreground color of the
        /// current block without committing it when the current block doesn't have content or 
        /// leading spaces.
        /// </summary>
        [TestMethod]
        public void TestSetForegroundColorNoContentNoLeadingSpaces()
        {
            const int testForegroundColor = 1;

            HtmlFile file;

            file = new HtmlFile();
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);

            file.SetForegroundColor(testForegroundColor);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[0].Blocks[0].ForegroundColor);

            file.SetForegroundColor(testForegroundColor + 1);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual((testForegroundColor + 1), file.Lines[0].Blocks[0].ForegroundColor);
        }

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetForegroundColor"/> commits the current block and 
        /// sets the foreground color of the new block when the current block has content.
        /// </summary>
        [TestMethod]
        public void TestSetForegroundColorWithContent()
        {
            const int testForegroundColor = 1;

            HtmlFile file;

            file = new HtmlFile();
            file.Append('T', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.IsTrue(file.Lines[0].HasContent);
            Assert.AreEqual(0, file.Lines[0].LeadingSpaces);

            file.SetForegroundColor(testForegroundColor);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[0].Blocks[1].ForegroundColor);
        }

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetForegroundColor"/> commits the current block and 
        /// sets the foreground color of the new block when the current block has leading spaces.
        /// </summary>
        [TestMethod]
        public void TestSetForegroundColorWithLeadingSpaces()
        {
            const int testForegroundColor = 1;

            HtmlFile file;

            file = new HtmlFile();
            file.Append(' ', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.IsFalse(file.Lines[0].HasContent);
            Assert.AreEqual(1, file.Lines[0].LeadingSpaces);

            file.SetForegroundColor(testForegroundColor);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testForegroundColor, file.Lines[0].Blocks[1].ForegroundColor);
        }

        #endregion // SetForegroundColor

        #region SetBackgroundColor

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetBackgroundColor"/> sets the background color of the
        /// current block without committing it when the current block doesn't have content or 
        /// leading spaces.
        /// </summary>
        [TestMethod]
        public void TestSetBackgroundColorNoContentNoLeadingSpaces()
        {
            const int testBackgroundColor = 1;

            HtmlFile file;

            file = new HtmlFile();
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);

            file.SetBackgroundColor(testBackgroundColor);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testBackgroundColor, file.Lines[0].Blocks[0].BackgroundColor);

            file.SetBackgroundColor(testBackgroundColor + 1);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual((testBackgroundColor + 1), file.Lines[0].Blocks[0].BackgroundColor);
        }

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetBackgroundColor"/> commits the current block and 
        /// sets the background color of the new block when the current block has content.
        /// </summary>
        [TestMethod]
        public void TestSetBackgroundColorWithContent()
        {
            const int testBackgroundColor = 1;

            HtmlFile file;

            file = new HtmlFile();
            file.Append('T', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.IsTrue(file.Lines[0].HasContent);
            Assert.AreEqual(0, file.Lines[0].LeadingSpaces);

            file.SetBackgroundColor(testBackgroundColor);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testBackgroundColor, file.Lines[0].Blocks[1].BackgroundColor);
        }

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetBackgroundColor"/> commits the current block and 
        /// sets the background color of the new block when the current block has leading spaces.
        /// </summary>
        [TestMethod]
        public void TestSetBackgroundColorWithLeadingSpaces()
        {
            const int testBackgroundColor = 1;

            HtmlFile file;

            file = new HtmlFile();
            file.Append(' ', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.IsFalse(file.Lines[0].HasContent);
            Assert.AreEqual(1, file.Lines[0].LeadingSpaces);

            file.SetBackgroundColor(testBackgroundColor);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(testBackgroundColor, file.Lines[0].Blocks[1].BackgroundColor);
        }

        #endregion // SetBackgroundColor

        #region SetBold

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetBold"/> sets the bold state of the current block 
        /// without committing it when the current block doesn't have content or leading spaces.
        /// </summary>
        [TestMethod]
        public void TestSetBoldNoContentNoLeadingSpaces()
        {
            HtmlFile file;

            file = new HtmlFile();
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);

            file.SetBold(true);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual(true, file.Lines[0].Blocks[0].Bold);

            file.SetBold(false);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.AreEqual(false, file.Lines[0].Blocks[0].Bold);
        }

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetBold"/> commits the current block and 
        /// sets the bold state of the new block when the current block has content.
        /// </summary>
        [TestMethod]
        public void TestSetBoldWithContent()
        {
            HtmlFile file;

            file = new HtmlFile();
            file.Append('T', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.IsTrue(file.Lines[0].HasContent);
            Assert.AreEqual(0, file.Lines[0].LeadingSpaces);

            file.SetBold(true);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(true, file.Lines[0].Blocks[1].Bold);
        }

        /// <summary>
        /// Ensures that <see cref="HtmlFile.SetBold"/> commits the current block and 
        /// sets the bold state of the new block when the current block has leading spaces.
        /// </summary>
        [TestMethod]
        public void TestSetBoldWithLeadingSpaces()
        {
            HtmlFile file;

            file = new HtmlFile();
            file.Append(' ', 4);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(1, file.Lines[0].Blocks.Count);
            Assert.IsFalse(file.Lines[0].HasContent);
            Assert.AreEqual(1, file.Lines[0].LeadingSpaces);

            file.SetBold(true);
            Assert.AreEqual(1, file.Lines.Count);
            Assert.AreEqual(2, file.Lines[0].Blocks.Count);
            Assert.AreEqual(true, file.Lines[0].Blocks[1].Bold);
        }

        #endregion // SetBold

        #region IndentationSpaces

        /// <summary>
        /// Ensures <see cref="HtmlFile.IndentationSpaces"/> returns <c>0</c> when the file
        /// has no lines.
        /// </summary>
        [TestMethod]
        public void TestIndentationSpacesWithNoLines()
        {
            HtmlFile htmlFile;

            htmlFile = new HtmlFile();

            Assert.AreEqual(0, htmlFile.IndentationSpaces);
        }

        /// <summary>
        /// Ensures <see cref="HtmlFile.IndentationSpaces"/> ignores blank lines when counting
        /// indentation spaces.
        /// </summary>
        [TestMethod]
        public void TestIndentationSpacesWithBlankLines()
        {
            HtmlFile htmlFile;

            htmlFile = new HtmlFile();

            // line 1: 4 leading spaces
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('T', 4);

            // line 2: 4 leading spaces
            htmlFile.StartNewLine();
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('e', 4);

            // line 3: 2 leading spaces, no content
            htmlFile.StartNewLine();
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);

            // line 4: 3 leading spaces
            htmlFile.StartNewLine();
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('t', 4);

            // should have 3 outdent spaces because of line 4
            // line 3 should have been ignored because it didn't have content
            Assert.AreEqual(3, htmlFile.IndentationSpaces);
        }

        /// <summary>
        /// Ensures <see cref="HtmlFile.IndentationSpaces"/> counts indentation spaces 
        /// correctly. 
        /// </summary>
        [TestMethod]
        public void TestIndentationSpaces()
        {
            HtmlFile htmlFile;

            htmlFile = new HtmlFile();

            // line 1: 4 leading spaces
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('T', 4);

            // line 2: 4 leading spaces
            htmlFile.StartNewLine();
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('e', 4);

            // line 3: 2 leading spaces
            htmlFile.StartNewLine();
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('s', 4);

            // line 4: 3 leading spaces
            htmlFile.StartNewLine();
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append(' ', 4);
            htmlFile.Append('t', 4);

            // should have 2 outdent spaces because of line 3
            Assert.AreEqual(2, htmlFile.IndentationSpaces);
        }

        #endregion // IndentationSpaces

        #endregion // Methods
    }

}
